//
//  EVEAPI.m
//  EVE Mac Suite
//
//  Created by Vadim Lozko on 3/20/09.
//  Copyright 2009 __Vadim__CompanyName__. All rights reserved.
//

#import "EVEAPI.h"
#import "EVEAPIDownloader.h"
#import "EVEAPIDownloaderRequest.h"
#import "EVEAPICoreDataController.h"

@implementation EVEAPI

@synthesize delegate;
@synthesize currentCharacters=_currentCharacters;

-(void)dealloc
{
	if(xmlDoc) {[xmlDoc release];}
	if(cachedUntil)	{[cachedUntil release];}
	if(updateTimer) {[updateTimer invalidate]; [updateTimer release];}
	[super dealloc];
}

-(NSManagedObjectContext*)managedObjectContext
{
	return EVECDContext;
}

//Must be subclassed
-(NSString*)APIDocumentType {return nil;}

//Must be subclassed
-(NSString*)xmlStorePath {return nil;}

//Subclassing optional
-(NSDictionary*)downloaderInfo
{
	return nil;
}

//Must be subclassed
-(void)updateCoreDataStore {}

//Must be subclassed
-(void)verifyCoreDataStore {}

-(void)update 
{
	if(xmlDoc)
	{
		[xmlDoc release];
		xmlDoc = nil;
	}
	NSError* error = nil;
	if([[NSFileManager defaultManager] fileExistsAtPath:[self xmlStorePath]])
	{
		xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[self xmlStorePath]]
													  options:NSXMLDocumentTidyXML 
														error:&error];
		if(!error && [self xmlDocValid:xmlDoc] && [self cachedDataCurrent])
		{
			[self verifyCoreDataStore];
			[self startUpdateTimer];
		} else if([self xmlDocValid:xmlDoc] && ![self cachedDataCurrent]) 
		{
			[self downloadLatestXMLDoc];
		} else {
			if(error)
			{
				NSLog(@"Error reading XML Doc: %@", [error localizedDescription]);
			} else {
				[self downloadLatestXMLDoc];
			}
		}
	} else {
		[self downloadLatestXMLDoc];
	}
}

-(void)forceUpdate
{
	if(xmlDoc)
	{
		[xmlDoc release];
		xmlDoc = nil;
	}
	[self downloadLatestXMLDoc];
}

-(BOOL)cachedDataCurrent
{
	NSError* error = nil;
	NSArray* serverTimeNodeArray = [xmlDoc nodesForXPath:@"//cachedUntil" error:&error];
	if(error || [serverTimeNodeArray count] != 1)
	{
		NSLog(@"Error parsing XML doc for cached until time");
		return YES;
	}
	//TODO: implement chinese localization. 
	NSString* serverCacheExpiresString = [[[serverTimeNodeArray objectAtIndex:0] stringValue] stringByAppendingString:@" +0000"];
	if(cachedUntil)
	{
		[cachedUntil release];
	}
	cachedUntil  = [[NSCalendarDate alloc] initWithString:serverCacheExpiresString calendarFormat:@"%Y-%m-%d %H:%M:%S %z"];
	NSCalendarDate* currentDate = [NSCalendarDate calendarDate];
	if([currentDate compare:cachedUntil] != NSOrderedAscending)
	{
		return NO;
	} else {
		return YES;
	}
}

-(BOOL)xmlDocValid:(NSXMLDocument*)document
{
	NSError* error = nil;
	NSArray* eveAPIVersionCheck = [document nodesForXPath:@"//eveapi" error:&error];
	if([eveAPIVersionCheck count] == 1)
	{
		return YES;
	} else {
		if(error)
		{
			NSLog(@"Error checking validity of xml doc: %@", [error localizedDescription]);
		}
		return NO;
	}
}

-(void)downloadLatestXMLDoc
{
	[[EVEAPIDownloader sharedDownloader] setDelegate:self];
	[[EVEAPIDownloader sharedDownloader] performAPIDownloadRequest:
	 [EVEAPIDownloaderRequest requestWithType:[self APIDocumentType] info:[self downloaderInfo] handler:self]];	
}

-(void)downloadRequestDidFinishForXMLDoc:(NSXMLDocument*)document 
{
	NSError* error = nil;
	if([self xmlDocValid:document])
	{
		NSData* xmlData = [document XMLData];
		if([[NSFileManager defaultManager] fileExistsAtPath:[self xmlStorePath]])
		{
			[[NSFileManager defaultManager] removeFileAtPath:[self xmlStorePath] handler:nil];
		}
		[xmlData writeToFile:[self xmlStorePath] options:NSXMLDocumentTidyXML error:&error];
		if(xmlDoc)
		{
			[xmlDoc release];
		}
		xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[self xmlStorePath]]
													  options:NSXMLDocumentTidyXML
														error:&error];
		[self cachedDataCurrent];
		//[NSThread detachNewThreadSelector:@selector(updateCoreDataStore) toTarget:self withObject:nil];
		[self updateCoreDataStore];
		[self startUpdateTimer];
	} else {
		if([[NSFileManager defaultManager] fileExistsAtPath:[self xmlStorePath]])
		{
			xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:[NSURL fileURLWithPath:[self xmlStorePath]]
														  options:NSXMLDocumentTidyXML
															error:&error];
			[self verifyCoreDataStore];
		}
		[self documentDidDownload:NO];
	}
	if(error)
	{
		[self documentDidDownload:NO];
		NSLog(@"Error writing xml file: %@", [error localizedDescription]);
	}
	[self documentDidDownload:YES];
}

//Subclassing optional
-(void)documentDidDownload:(BOOL)success;
{}

//Subclassing optional
-(void)updateDidFinish:(NSNumber*)success 
{
	[[NSNotificationCenter defaultCenter] postNotificationName:[self APIDocumentType]
														object:self 
													  userInfo:[NSDictionary dictionaryWithObject:success 
																						   forKey:NOTIFICATION_SUCCESS_UPDATE_KEY]];
}

-(void)downloadRequestDidFailWithError:(NSError*)error
{
	[self updateDidFinish:(NSNumber*)kCFBooleanFalse];
}

-(void) startUpdateTimer
{
	NSError* error = nil;
	NSArray* serverTimeNodeArray = [xmlDoc nodesForXPath:@"//cachedUntil" error:&error];
	if(error || [serverTimeNodeArray count] != 1)
	{
		NSLog(@"Error parsing XML doc for cached until time");
		return;
	}
	if(!cachedUntil)
	{
		NSString* serverCacheExpiresString = [[[serverTimeNodeArray objectAtIndex:0] stringValue] stringByAppendingString:@" +0000"];
		cachedUntil  = [[NSCalendarDate alloc] initWithString:serverCacheExpiresString calendarFormat:@"%Y-%m-%d %H:%M:%S %z"];
	}
	NSTimeInterval timeToUpdate = [cachedUntil timeIntervalSinceDate:[NSDate date]];
	
	if(updateTimer)
	{
		[updateTimer invalidate];
		[updateTimer release];
	}
	updateTimer = [[NSTimer scheduledTimerWithTimeInterval:timeToUpdate target:self selector:@selector(update) userInfo:nil repeats:NO] retain];
}


-(void)invalidateTimers
{
	if(updateTimer)
	{
		[updateTimer invalidate];
		[updateTimer release];
		updateTimer = nil;
	}
}

@end


@implementation EVEAPI (ParseDelegate)

-(void)parserDidStartDocument:(NSXMLParser*)parser
{
	_currentCharacters = [[NSMutableString alloc] initWithString:@""];
}

-(void)parserDidEndDocument:(NSXMLParser*)parser
{
	[_currentCharacters release];
	[parser release];
}

@end